//////////////////   碰 、杠 、胡 请求  //////////////////
import { retry } from 'rxjs';
import {checkHu}  from './checkHu';
import {adminTest}  from './hzmj.service';
import {resp}  from '../socket/message.utils';
import { defaultConfig } from '@game/config/config';

export async function peng(game, userId, hzmjService,moveToNextUser) {
  let seatData = game.gameSeats.find((item) => item.userId == userId);
  if (seatData == null) {
    console.log("can't find user game data.");
    return false;
  }
  //如果是他出的牌，则忽略
  if (game.turn == seatData.seatIndex) {
    console.log("it's your turn.");
    return false;
  }

  //如果没有碰的机会，则不能再碰
  if (seatData.canPeng == false) {
    console.log('seatData.peng == false');
    return false;
  }

  //和的了，就不要再来了
  if (seatData.hued) {
    console.log('you have already hued. no kidding plz.');
    return false;
  }

  //如果有人可以胡牌，则需要等待 至于要这样恶心的循环写么
  let i = game.turn;
  while (true) {
    i = (i + 1) % game.gameSeats.length;
    if (i == game.turn) {
      break;
    } else {
      let ddd = game.gameSeats[i];
      if (ddd.canHu && i != seatData.seatIndex) {
        return;
      }
    }
  }

  let pai = game.chuPai;
  //验证手上的牌的数目
  let c = seatData.countMap[pai];
  if (c == null || c < 2) {
    console.log('pai:' + pai + ',count:' + c);
    console.log(seatData.holds);
    console.log('lack of mj.');
    return;
  }
  clearAllOptions(game);
  delete game.guoshoupeng[userId]; //移除过手碰限制
  await hzmjService.redisService.hset({
    key: 'game' + game.roomId,
    value: { ...game },
    expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
  });
  //进行碰牌处理
  //扣掉手上的牌
  //从此人牌中扣除
  for (let i = 0; i < 2; ++i) {
    let index = seatData.holds.indexOf(pai);
    if (index == -1) {
      console.log("can't find mj.");
      return false;
    }
    seatData.holds.splice(index, 1);
    seatData.countMap[pai]--;
  }
  seatData.penggangs.push(['peng', pai]);
  game.chuPai = -1;
 
  //广播通知其它玩家
 await hzmjService.gateway.broadcastInRoom({
    seats: game.gameSeats,
    roomId: game.roomId,
    userId: seatData.userId,
    message: { userId: seatData.userId, pai: pai },
    type: resp.peng_notify,
    includSender: true,
  });

  //广播通知玩家出牌方
  seatData.canChuPai = true;
  //碰的玩家打牌
  moveToNextUser(game, seatData.seatIndex);



  await hzmjService.gateway.broadcastInRoom({
    seats: game.gameSeats,
    roomId: game.roomId,
    userId: seatData.userId,
    message: seatData.userId,
    type: resp.game_chupai,
    includSender: true,
  });
  return true

}

export async function gang(game, userId, pai, hzmjService,moveToNextUser,doUserMoPai) {
  let seatData = game.gameSeats.find((item) => item.userId == userId);
  if (seatData == null) {
    console.log("can't find user game data.");
    return false;
  }
  let seatIndex = seatData.seatIndex;

  //如果没有杠的机会，则不能再杠
  if (seatData.canGang == false) {
    console.log('seatData.gang == false');
    return false;
  }

  //和的了，就不要再来了
  if (seatData.hued) {
    console.log('you have already hued. no kidding plz.');
    return false;
  }

  if (!seatData.gangPai.includes(Number(pai))) {
    console.log("the given pai can't be ganged.");
    return false;
  }

  delete game.guoshoupeng[userId]; //移除过手碰

  let numOfCnt = seatData.countMap[pai];

  let gangtype = '';
  //弯杠 去掉碰牌
  if (numOfCnt == 1) {
    gangtype = 'wangang';
  } else if (numOfCnt == 3) {
    gangtype = 'diangang';
  } else if (numOfCnt == 4) {
    gangtype = 'angang';
  } else {
    console.log('invalid pai count.');
    return false;
  }

  game.chuPai = -1;
  clearAllOptions(game);
  seatData.canChuPai = false;

  await hzmjService.gateway.broadcastInRoom({
    seats: game.gameSeats,
    roomId: game.roomId,
    userId: seatData.userId,
    message: { userId: seatData.userId, pai: pai, gangtype: gangtype },
    type: resp.hangang_notify,
    includSender: true,
  });
  //如果是弯杠，则需要检查是否可以抢杠
  let turnSeat = game.gameSeats[game.turn];
  if (numOfCnt == 1) {
    let canQiangGang =await checkCanQiangGang(game, turnSeat, seatData, pai,hzmjService);
    if (canQiangGang) {
      return false;
    }
  }

  return doGang(game, turnSeat, seatData, gangtype, numOfCnt, pai, hzmjService,moveToNextUser,doUserMoPai);
}

export async function doGang(
  game,
  turnSeat,
  seatData,
  gangtype,
  numOfCnt,
  pai,
  hzmjService,
  moveToNextUser,doUserMoPai
) {
  let seatIndex = seatData.seatIndex;
  let gameTurn = turnSeat.seatIndex;

  let isZhuanShouGang = false;
  if (gangtype == 'wangang') {
    for (let i = 0; i < seatData.penggangs.length; i++) {
      if (
        seatData.penggangs[i][0] == 'peng' &&
        seatData.penggangs[i][1] == pai
      ) {
        seatData.penggangs[i][0] = 'wangang';
        break;
      }
    }
    //如果最后一张牌不是杠的牌，则认为是转手杠
    if (seatData.holds[seatData.holds.length - 1] != pai) {
      isZhuanShouGang = true;
    }
  }

  //记录下玩家的杠牌
  if (gangtype == 'angang') {
    seatData.penggangs.push(['angang', pai]);
    recordUserAction(game, seatData, 'angang');
  } else if (gangtype == 'diangang') {
    seatData.penggangs.push(['diangang', pai]);
    recordUserAction(game, seatData, 'diangang', gameTurn);
    let fs = turnSeat;
    recordUserAction(game, fs, 'fanggang', seatIndex);
  } else if (gangtype == 'wangang') {
    if (isZhuanShouGang == false) {
      recordUserAction(game, seatData, 'wangang');
    } else {
      recordUserAction(game, seatData, 'zhuanshougang');
    }
  }
  //进行碰牌处理
  //扣掉手上的牌
  //从此人牌中扣除
  for (let i = 0; i < numOfCnt; ++i) {
    let index = seatData.holds.indexOf(pai);
    if (index == -1) {
      console.log(seatData.holds);
      console.log("can't find mj.");
      return false;
    }
    seatData.holds.splice(index, 1);
    seatData.countMap[pai]--;
  }

  await checkTingPai(game, seatData,hzmjService);
  //通知其他玩家，有人杠了牌

 await hzmjService.gateway.broadcastInRoom({
    seats: game.gameSeats,
    roomId: game.roomId,
    userId: seatData.userId,
    message: { userId: seatData.userId, pai: pai, gangtype: gangtype },
    type: resp.gang_notify,
    includSender: true,
  });
  //只能放在这里。因为过手就会清除杠牌标记
  seatData.lastFangGangSeat = gameTurn;
  //变成自己的轮子
  moveToNextUser(game, seatIndex);
  //再次摸牌
  doUserMoPai(game, true);

  return true

}


export async function hu(game, userId, hzmjService,doGameOver) {
  let seatData = game.gameSeats.find((item) => item.userId == userId);
  if (seatData == null) {
    console.log("can't find user game data.");
    return false;
  }

  let seatIndex = seatData.seatIndex;

  //如果他不能和牌，那和个啥啊
  if(seatData.canHu == false){
    console.log("invalid request.");
    return false;
  }

  //和的了，就不要再来了
  if (seatData.hued) {
    console.log('you have already hued. no kidding plz.');
    return false;
  }

  // let isDaHu_BBH=JSON.parse(game.isDaHu)
  // 获取规则
  let mashu=game.mashu
  let hz2=game.hz2
  let leng =mashu;
 if( seatData.countMap[game.laizi[0]]>0){
  leng =mashu
 }else{
  leng =hz2==1?mashu+2:mashu
 }
  let numOfMJ = game.mahjongs.length - game.currentIndex;
  leng =leng-numOfMJ>0?numOfMJ:leng
 
  if( !game.round|| game.round.length==0){
    game.round=[]
    game.zhongma=[]
    for (let index = 0; index < leng; index++) {
      let pai1 = game.mahjongs[game.currentIndex];
      game.currentIndex++;
      const rank1 = Math.floor(pai1 % 9);
      game.round.push((seatData.seatIndex+rank1-1)%4)
      game.zhongma.push(pai1)
    }
   
  }
  //标记为和牌
  seatData.hued = true;
  let hupai = game.chuPai;
  let isZimo = false;
  // hu的是当前轮次的杠说明是ming的
  let turnSeat = game.gameSeats[game.turn];
  seatData.isGangHu = turnSeat.lastFangGangSeat >= 0;
  let notify = -1;
  let type = '';
  if (game.qiangGangContext != null) {
    let gangSeat = game.qiangGangContext.seatData;
    hupai = game.qiangGangContext.pai;
    notify = hupai;
    const  ac:any= recordUserAction(
      game,
      seatData,
      'qiangganghu',
      gangSeat.seatIndex,
    );
    ac.iszimo = false;
    type = 'qiangganghu';
    seatData.isQiangGangHu = true;
    game.qiangGangContext.isValid = false;
    game.yipaoduoxiang++;

    for (let i = 0; i < seatData.tingMap.length; i++) {
      if (seatData.tingMap[i][1].includes(hupai)) {
        recordUserAction(game,seatData,seatData.tingMap[i][0], gangSeat.seatIndex)
      }
    }

    //将牌添加到玩家的手牌列表，供前端显示
    seatData.holds.push(hupai);
    if (seatData.countMap[hupai]) {
      seatData.countMap[hupai]++;
    } else {
      seatData.countMap[hupai] = 1;
    }
    recordUserAction(game, seatData, 'beiqianggang', gangSeat.seatIndex);
    //缺一个推送展示
  } else if (game.chuPai == -1) {
    //hupai = seatData.holds[seatData.holds.length - 1];
    notify = -1;
    if (seatData.isGangHu) {
      if (turnSeat.lastFangGangSeat == seatIndex) {
        const  ac:any = recordUserAction(game, seatData, 'ganghua');
        type = 'ganghua';
        ac.iszimo = true;
      } 
    } else {
      const  ac:any = recordUserAction(game, seatData, 'zimo');
      type = 'zimo';
      ac.iszimo = true;
    }
    isZimo = true;
    seatData.numZiMo++;
  }

  game.firstHupai = seatIndex;

  seatData.iszimo = isZimo;

  clearAllOptions(game, seatData);

  await doGameOver(game, seatData.userId,false,type,notify,isZimo);
}

export async function guo(game, userId, hzmjService,moveToNextUser,doUserMoPai) {
  let seatData = game.gameSeats.find((item) => item.userId == userId);
  if (seatData == null) {
    console.log("can't find user game data.");
    return false;
  }
  let seatIndex = seatData.seatIndex;

  //如果玩家没有对应的操作，则也认为是非法消息
  if ((seatData.canGang || seatData.canPeng || seatData.canHu) == false) {
    console.log('no need guo.');
    return false;
  }

  //如果是玩家自己的轮子，不是接牌，则不需要额外操作
  let doNothing = game.chuPai == -1 && game.turn == seatIndex;

  if (game.chuPai != -1) {
    if (game.guoshoupeng[userId] == null) game.guoshoupeng[userId] = {};
    game.guoshoupeng[userId][game.chuPai] = 1;
  }
  //这里还要处理过胡的情况
  if (game.chuPai >= 0 && seatData.canHu) {
    seatData.guoHuTime++;
  }

  clearAllOptions(game, seatData);

  await hzmjService.redisService.hset({
    key: 'game' + game.roomId,
    value: { ...game },
    expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
  });
  if (doNothing) {
    await moveToNextUser(game, seatIndex);
    return false;
  }

  //如果还有人可以操作，则等待
  for (let i = 0; i < game.gameSeats.length; ++i) {
    let ddd = game.gameSeats[i];
    if (hasOperations(ddd)) {
      return false;
    }
  }

  //如果是已打出的牌，则需要通知。
  if (game.chuPai >= 0) {
    let uid = game.gameSeats[game.turn].userId;
   await hzmjService.gateway.broadcastInRoom({
      seats: game.gameSeats,
      roomId: game.roomId,
      userId: seatData.userId,
      message: { userId: uid, pai: game.chuPai },
      type: resp.guo_notify,
      includSender: true,
    });

    seatData.folds.push(game.chuPai);
    game.chuPai = -1;
  }

  let qiangGangContext = game.qiangGangContext;
  //清除所有的操作
  clearAllOptions(game, seatData);
  await hzmjService.redisService.hset({
    key: 'game' + game.roomId,
    value: { ...game },
    expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
  });


  console.log('过了后判断轮次摸牌');
  if (qiangGangContext != null && qiangGangContext.isValid) {
    console.log('不抢杠接着开杠');
    doGang(
      game,
      qiangGangContext.turnSeat,
      qiangGangContext.seatData,
      'wangang',
      1,
      qiangGangContext.pai,
      hzmjService,
      moveToNextUser,doUserMoPai
    );
  } else {
    //下家摸牌
  await  moveToNextUser(game);
  await  doUserMoPai(game);
  return true

  }
}

export async function checkTingPai(game: any, seatData: any,hzmjService) {
  //检测特殊番数
  let isHu: any = checkHu.doCheckTing(seatData.holds, game.laizi,game.isCsJiang); //检查平胡
  seatData.tingMap=[]

  if (isHu.length > 0) {
    console.log('可胡:', checkHu.getName(isHu));
    seatData.tingMap = seatData.tingMap.concat([["normal",isHu]]);
    seatData.pattern = 'normal';
   await hzmjService.gateway.send({
      ...seatData,
      roomId: game.roomId,
      type: resp.game_ting,
      message: { tingMap: seatData.tingMap, pattern: seatData.pattern },
    });
  }
 
  
}


export async function clearAllOptions(game,seatData=null){
	let fnClear = function(sd){
        sd.canChi = false;
        sd.chiPai = [];
		sd.canPeng = false;
		sd.canGang = false;
		sd.gangPai = [];
		sd.canHu = false;
		sd.lastFangGangSeat = -1;	
	}
	if(seatData){
		fnClear(seatData);
	}
	else{
		game.qiangGangContext = null;
		for(let i = 0; i < game.gameSeats.length; ++i){
			fnClear(game.gameSeats[i]);
		}
	}
}

export async function recordUserAction(game,seatData,type,target=null){
  let d = {type:type,targets:[]};
  if(target != null){
    if(typeof(target) == 'number'){
      d.targets.push(target);	
    }
    else{
      d.targets = target;
    }
  }
  else{
    for(let i = 0; i < game.gameSeats.length; ++i){
      let s = game.gameSeats[i];
      if(i != seatData.seatIndex && s.hued == false){
        d.targets.push(i);
      }
    }		
  }
  seatData.actions.push(d);
  return d;
}

export async function checkCanQiangGang(game,turnSeat,seatData,pai,hzmjService){
  let hasActions = false;
  for(let i = 0; i < game.gameSeats.length; ++i){
      //杠牌者不检查
      if(seatData.seatIndex == i){
          continue;
      }
      let ddd = game.gameSeats[i];
      //已经和牌的不再检查
      if(ddd.hued){
          continue;
      }

     await checkCanHu(game,ddd,pai);
      if(ddd.canHu){
      await  sendOperations(game,ddd,pai,hzmjService);
          hasActions = true;
      }
  }
  if(hasActions){
      game.qiangGangContext = {
          turnSeat:turnSeat,
          seatData:seatData,
          pai:pai,
          isValid:true,
      }
  }
  else{
      game.qiangGangContext = null;
  }
  return game.qiangGangContext != null;
}


export function  hasOperations(seatData) {
  if (seatData.canGang || seatData.canPeng || seatData.canHu) {
    return true;
  }
  return false;
}

export async function checkCanHu(game, seatData, targetPai) {
  //game.lastHuPaiSeat = -1;
  seatData.canHu = false;

  let count = 0;
  for (let i = 0; i < game.laizi.length; i++) {
    //鬼牌大于等于4，直接胡牌
    count += seatData.countMap[game.laizi[i]];
  }
  if (count > 3) {
    seatData.canHu = true;
  }
  // 累计计算
  for (let i = 0; i < seatData.tingMap.length; i++) {
    if (seatData.tingMap[i][1].includes(targetPai)) {
      seatData.canHu = true;
      break;
    }
  }
}

export async function sendOperations(game, seatData, pai,hzmjService) {
  if (hasOperations(seatData)) {
    //保存游戏  socket消息过快 缓存数据没更新到 导致有动作但是状态不对
    await hzmjService.redisService.hset({
      key: 'game' + game.roomId,
      value: { ...game },
      expire: defaultConfig.scoreCacheTime, // 3秒  为了就是瞬时刷新过快 导致的mysql问题
    });
    if (pai == -1) {
      //起手
      pai = seatData.holds[seatData.holds.length - 1];
    }

    if (seatData.canHu) {
      let data:any = { pai: pai };
      data.hu = true;
       //如果可以有操作，则进行操作
      await hzmjService.gateway.send({
        ...seatData,
        roomId:game.roomId,
        message: data,
        type: this.resp.game_action,
      });
    }
    if (seatData.canGang) {
      let data:any = { pai: pai };
      data.gang = true;
      data.gangpai = seatData.gangPai;
       //如果可以有操作，则进行操作
      await hzmjService.gateway.send({
        ...seatData,
        roomId:game.roomId,
        message: data,
        type: this.resp.game_action,
      });
    }
    if (seatData.canPeng) {
      let data:any = { pai: pai };
      data.peng = true;
       //如果可以有操作，则进行操作
      await hzmjService.gateway.send({
        ...seatData,
        roomId:game.roomId,
        message: data,
        type: this.resp.game_action,
      });
    }
  }
}